package com.yunxi.service.localService.impl.otd;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.yunxi.core.service.ServiceImplPlus;
import com.yunxi.core.util.BeanTools;
import com.yunxi.core.util.StringUtil;
import com.yunxi.core.web.ApiResult;
import com.yunxi.core.web.ResponseUtil;
import com.yunxi.dao.otd.OtdOrderCirWeekMapper;
import com.yunxi.model.otd.OtdOrderCir;
import com.yunxi.model.otd.OtdOrderCirMonth;
import com.yunxi.model.otd.OtdOrderCirWeek;
import com.yunxi.model.otd.OtdOrderCirWeekVersion;
import com.yunxi.otd.pojo.OtdOrderCirWeekImportVO;
import com.yunxi.otd.pojo.OtdOrderCirWeekPageVO;
import com.yunxi.otd.pojo.OtdOrderCirWeekQueryVO;
import com.yunxi.otd.pojo.OtdOrderCirWeekReleaseVO;
import com.yunxi.otd.pojo.OtdOrderCirWeekVO;
import com.yunxi.service.localService.CodeCreateService;
import com.yunxi.service.localService.VehicleProductViewService;
import com.yunxi.service.localService.otd.OtdOrderCirService;
import com.yunxi.service.localService.otd.OtdOrderCirWeekService;
import com.yunxi.service.localService.otd.OtdOrderCirWeekVersionService;
import com.yunxi.service.localService.otd.OtdOrderSoService;
import com.yunxi.service.localService.otd.OtdProduceCalendarService;
import com.yunxi.service.localService.otd.VehicleConfigConstraintService;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.regex.Pattern;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

/**
 * <p>
 * 周CIR预测 服务实现类
 * </p>
 *
 * @author XUQI
 * @since 2019-10-14
 */
@Service
public class OtdOrderCirWeekServiceImpl extends ServiceImplPlus<OtdOrderCirWeekMapper, OtdOrderCirWeek> implements
    OtdOrderCirWeekService {

    @Autowired
    @Qualifier(value = "otdOrderCirWeekVersionServiceImpl")
    OtdOrderCirWeekVersionService weekVersionService;

    @Autowired
    @Qualifier(value = "vehicleProductViewServiceImpl")
    VehicleProductViewService productService;

    @Autowired
    @Qualifier("otdProduceCalendarServiceImpl")
    OtdProduceCalendarService calendarService;

    @Autowired
    @Qualifier(value = "otdOrderCirServiceImpl")
    OtdOrderCirService cirService;

    @Autowired
    @Qualifier("otdProduceCalendarServiceImpl")
    OtdProduceCalendarService produceCalendarService;

    @Autowired
    @Qualifier(value = "otdOrderSoServiceImpl")
    OtdOrderSoService soService;

    @Autowired
    @Qualifier("codeCreateServiceImpl")
    CodeCreateService code;


    @Autowired
    @Qualifier("vehicleConfigConstraintServiceImpl")
    VehicleConfigConstraintService configConstraintService;


    /**
     * 查询周CIR预测
     *
     * @param queryVO 查询VO
     * @return PageInfo
     */
    @Override
    public ApiResult page(OtdOrderCirWeekQueryVO queryVO) {
        Map map = BeanTools.bean2map(queryVO);
        OtdOrderCirWeekPageVO data = new OtdOrderCirWeekPageVO();
        List<String> weeks = calendarService.weekListByYearWeek(queryVO.getYear(), queryVO.getWeek());
        if (CollectionUtils.isEmpty(weeks)) {
            return ResponseUtil.fail(-1, "请输入正确的周数");
        }
        map.put("weeks", weeks);
        data.setTotal(baseMapper.selectOrderCirWeekCount(map));
        data.setList(baseMapper.selectOrderCirWeek(map));
        return ResponseUtil.ok(data);
    }

    /**
     * 修改数量
     *
     * @param weekVO 周预测VO
     * @return ApiResult
     */
    @Override
    public ApiResult modify(OtdOrderCirWeekVO weekVO) {
        // 查询周预测数据
        LambdaQueryWrapper<OtdOrderCirWeek> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OtdOrderCirWeek::getVersionId, weekVO.getVersionId())
            .eq(OtdOrderCirWeek::getYear, weekVO.getYear())
            .eq(OtdOrderCirWeek::getWeek, weekVO.getWeek())
            .eq(OtdOrderCirWeek::getWorks, weekVO.getWorks())
            .eq(OtdOrderCirWeek::getProductCode, weekVO.getProductCode());
        if (StringUtils.isEmpty(weekVO.getCustomPackCode())) {
            queryWrapper.isNull(OtdOrderCirWeek::getCustomPackCode);
        } else {
            queryWrapper.eq(OtdOrderCirWeek::getCustomPackCode, weekVO.getCustomPackCode());
        }
        OtdOrderCirWeek cirWeek = baseMapper.selectOne(queryWrapper);
        if (cirWeek == null) {
            // 新增一行
            cirWeek = new OtdOrderCirWeek();
            BeanUtils.copyProperties(weekVO, cirWeek);
        }
        cirWeek.setOrderNum(weekVO.getOrderNum());
        saveOrUpdate(cirWeek);
        return ResponseUtil.ok();
    }

    /**
     * 导入
     *
     * @param importVO 导入VO
     * @return ApiResult
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApiResult importData(OtdOrderCirWeekImportVO importVO) {
        // 年、周
        String year = importVO.getYear();

        OtdOrderCirWeekVersion weekVersion = null;
        //是否新增版本
        boolean isAdd = StringUtils.isEmpty(importVO.getVersionId());
        if (isAdd) {
            if (StringUtils.isEmpty(importVO.getMadeVersion())) {
                return ResponseUtil.fail(-1, "新增版本名称不能为空");
            }
            // 验证名称唯一
            LambdaQueryWrapper<OtdOrderCirWeekVersion> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OtdOrderCirWeekVersion::getMadeVersion, importVO.getMadeVersion());
            int count = weekVersionService.count(wrapper);
            if (count > 0) {
                return ResponseUtil.fail(-1, "版本名称已存在");
            }
            // 新增版本
            weekVersion = new OtdOrderCirWeekVersion();
            weekVersion.setMadeVersion(importVO.getMadeVersion());
            weekVersion.setIsDefault(0);
            weekVersion.setState("1");
            weekVersionService.save(weekVersion);
        } else {
            // 查询制作版本
            weekVersion = weekVersionService.getById(importVO.getVersionId());
            if (weekVersion == null) {
                return ResponseUtil.fail(-1, "未找到版本信息");
            }

            //删除已制作数据
            LambdaQueryWrapper<OtdOrderCirWeek> wrapper = new LambdaQueryWrapper<>();
            wrapper.eq(OtdOrderCirWeek::getVersionId, weekVersion.getId());
            this.remove(wrapper);

        }
        //制作版本ID
        String versionId = weekVersion.getId();

        // 导入数据集合
        List<Map<String, Object>> dataList = importVO.getDataList();
        if (CollectionUtils.isEmpty(dataList)) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseUtil.fail(-1, "导入数据为空");
        }

        // 验证导入数据是否存在重复行
        try {
            checkImportDataRepeat(dataList);
        } catch (Exception e) {
            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
            return ResponseUtil.fail(-1, e.getMessage());
        }

        // 循环每一行导入数据
        List<OtdOrderCirWeek> cirWeekList = new ArrayList<>();
        for (Map<String, Object> data : importVO.getDataList()) {
            // 产品CODE
            String productCode = productService
                .findProductCodeBySub((String) data.get("配置"), (String) data.get("内饰色"),
                    (String) data.get("外饰色"));
            if (StringUtils.isEmpty(productCode)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResponseUtil.fail(-1, "产品信息填写错误");
            }
            //选装包CODES
            String customPackCode = (String) data.get("选装包");
            if (customPackCode != null) {
                customPackCode = StringUtil.customPackCodeSort(customPackCode.replace("/", ","));
            }

            // 添加周预测数据
            for (Entry<String, Object> entry : data.entrySet()) {
                // 周数
                String key = entry.getKey();
                // 数量
                Object value = entry.getValue();
                // 判断如果列头为1~53的数字时
                if (checkWeek(key)) {
                    // 周数
                    String weekNum = key.length() == 1 ? "0" + key : key;
                    int orderNum = StringUtils.isEmpty(value) ? 0 : Integer.parseInt((String) value);

                    // 大于0则新增
                    if (orderNum > 0) {
                        OtdOrderCirWeek order = new OtdOrderCirWeek();
                        order.setVersionId(versionId);
                        order.setYear(year);
                        order.setWeek(weekNum);
                        order.setProductCode(productCode);
                        order.setCustomPackCode(StringUtils.isEmpty(customPackCode) ? null : customPackCode);
                        order.setWorks("AP21");
                        order.setOrderNum(orderNum);
                        cirWeekList.add(order);
                    }
                }
            }
        }
        if (!CollectionUtils.isEmpty(cirWeekList)) {
            saveBatch(cirWeekList);
        }
        return ResponseUtil.ok();
    }


    /**
     * 释放周预测
     *
     * @param releaseVO releaseVO
     * @return ApiResult
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public ApiResult release(OtdOrderCirWeekReleaseVO releaseVO) {
        String versionId = releaseVO.getWeekVersionId();
        String year = releaseVO.getYear();
        List<String> weeks = releaseVO.getWeeks();
        if (StringUtils.isEmpty(versionId)) {
            return ResponseUtil.fail(-1, "未选择释放版本");
        }
        if (CollectionUtils.isEmpty(weeks)) {
            return ResponseUtil.fail(-1, "未选择释放周");
        }
        weeks.forEach(week -> week = week.length() == 1 ? "0" + week : week);

        //// 查询需要释放的周预测
        LambdaQueryWrapper<OtdOrderCirWeek> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OtdOrderCirWeek::getYear, year).in(OtdOrderCirWeek::getWeek, weeks)
            .eq(OtdOrderCirWeek::getVersionId, versionId);
        List<OtdOrderCirWeek> cirWeekList = baseMapper.selectList(queryWrapper);
        if (CollectionUtils.isEmpty(cirWeekList)) {
            return ResponseUtil.fail(-1, "未找到可释放的周预测数据");
        }
        // 删除原释放CIR数量
        cirService.deleteCirOrderByYearWeeks(year, weeks);

        List<OtdOrderCir> cirList = new ArrayList<>();
        for (OtdOrderCirWeek cirWeek : cirWeekList) {
            if (cirWeek.getOrderNum() == 0) {
                // 数量0，跳过
                continue;
            }

            // 根据年周查询生产工作日历
            List<Date> days = produceCalendarService.findWorkDayByYearWeek(cirWeek.getYear(), cirWeek.getWeek());
            if (CollectionUtils.isEmpty(days)) {
                TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
                return ResponseUtil.fail(-1, cirWeek.getYear() + "年" + cirWeek.getWeek() + "周没有维护工作日");
            }

            //每天平均数4
            int avgNum = cirWeek.getOrderNum() / days.size();
            // 余数
            int modNum = cirWeek.getOrderNum() % days.size();

            /////平均分配数量
            for (int i = 1; i <= days.size(); i++) {
                // 需求数量
                int orderNum = avgNum;

                if (orderNum == 0) {
                    // 当总数小于天数时
                    if (modNum == 0) {
                        break;
                    }
                    orderNum = 1;
                    modNum--;
                } else {
                    // 判断余数
                    if (modNum > 0) {
                        orderNum++;
                        modNum--;
                    }
                }

                //// 添加CIR订单
                OtdOrderCir orderCir = new OtdOrderCir();
                orderCir.setPlanNo(code.createCode("MP", "yyMMdd", 5));
                orderCir.setProductCode(cirWeek.getProductCode());
                orderCir.setCustomPackCode(cirWeek.getCustomPackCode());
                orderCir
                    .setCarName(soService.generateCarName(cirWeek.getProductCode(), cirWeek.getCustomPackCode()));
                orderCir.setDemandDate(days.get(i - 1));
                orderCir.setOrderNum(orderNum);
                orderCir.setWorks("AP21");
                cirList.add(orderCir);

            }
        }
        if (!CollectionUtils.isEmpty(cirList)) {
            cirService.saveBatch(cirList);
        }
        return ResponseUtil.ok();
    }

    /**
     * 验证导入数据是否存在重复行
     *
     * @param dataList 导入数据
     */
    private void checkImportDataRepeat(List<Map<String, Object>> dataList) {
        // List<产品CODE+选装包CODE>
        List<String> checkRepeatList = new ArrayList<>();
        for (Map<String, Object> map : dataList) {
            String vehicleCode = (String) map.get("配置");
            String inCode = (String) map.get("内饰色");
            String outCode = (String) map.get("外饰色");
            String customPackCode = StringUtil.customPackCodeSort((String) map.get("选装包"));
            if (StringUtils.isEmpty(vehicleCode)) {
                throw new RuntimeException("第" + (checkRepeatList.size() + 1) + "行配置不能为空");
            }
            if (StringUtils.isEmpty(inCode)) {
                throw new RuntimeException("第" + (checkRepeatList.size() + 1) + "行内饰色不能为空");
            }
            if (StringUtils.isEmpty(outCode)) {
                throw new RuntimeException("第" + (checkRepeatList.size() + 1) + "行外饰色不能为空");
            }

            // 选装包校验
            if (!StringUtils.isEmpty(customPackCode)) {
                // 是否正确、是否存在互斥
                List<String> packages = Arrays.asList(customPackCode.split("/"));
                boolean check = configConstraintService.checkExcludeCustomPackCode(packages, vehicleCode);
                if(!check){
                    throw new RuntimeException("选装包存在互斥：" + customPackCode);
                }
            }

            // 产品CODE
            String code = vehicleCode + inCode + outCode;
            // 验证导入数据是否存在重复行
            if (!checkRepeatList.contains(code + customPackCode)) {
                checkRepeatList.add(code + customPackCode);
            } else {
                throw new RuntimeException("第" + (checkRepeatList.size() + 1) + "行重复");
            }
        }
    }

    /**
     * 校验是否为周数（1-53）
     *
     * @param month 月份
     * @return 是 true 否 false
     */
    private boolean checkWeek(String month) {
        Pattern pattern = Pattern.compile("^0?[1-9]|[1-4][0-9]|[0-5][0-3]$");
        return pattern.matcher(month).matches();
    }

}
